package functional.functionalannotation;

/**
 * @ClassName FunctionalAnnotation
 * @PackageName functional.functionalAnnotation
 * @projectName myThread
 * @Description 
 * @Author games
 * @Date 2025/8/26 下午1:14
 * @Version 1.0
 */
public class FunctionalAnnotation {

    /**
     * 方法引用和 Lambda 表达式必须被赋值，同时编译器需要识别类型信息以确保类型正确。
     * Lambda 表达式包含类型推导（编译器会自动推导出类型信息，避免了程序员显式地声明）。编译器必须能够以某种方式推导出 x 的类型。
     * <p>
     * 为了解决这个问题，Java 8 引入了 java.util.function 包。它包含一组接口，这些接口是 Lambda 表达式和方法引用的目标类型。
     * 每个接口只包含一个抽象方法，称为函数式方法。
     */

    @FunctionalInterface
    interface Functional {
        String goodbye(String arg);
    }

    interface FunctionalNoAnn {
        String goodbye(String arg);
    }

    /*
    @FunctionalInterface
    interface NotFunctional {
      String goodbye(String arg);
      String hello(String arg); //单个 抽象方法
    }
    产生错误信息:
    NotFunctional is not a functional interface
    multiple non-overriding abstract methods
    found in interface NotFunctional
    */

    public String goodbye(String arg) {
        return "Goodbye, " + arg;
    }

    public static void main(String[] args) {
        /**
         * @FunctionalInterface 注解是可选的; Java 在 main() 中把 Functional 和 FunctionalNoAnn 都当作函数式接口。 在 NotFunctional 的定义中可看到@FunctionalInterface 的作用：接口中如果有多个方法则会产生编译期错误。
         *
         * 仔细观察在定义 f 和 fna 时发生了什么。 Functional 和 FunctionalNoAnn 定义接口，然而被赋值的只是方法 goodbye()。首先，这只是一个方法而不是类；其次，它甚至都不是实现了该接口的类中的方法。这是添加到Java 8中的一点小魔法：如果将方法引用或 Lambda 表达式赋值给函数式接口（类型需要匹配），Java 会适配你的赋值到目标接口。 编译器会自动包装方法引用或 Lambda 表达式到实现目标接口的类的实例中。
         *
         * 尽管 FunctionalAnnotation 确实适合 Functional 模型，
         * 但 Java不允许我们像fac定义中的那样，将 FunctionalAnnotation 直接赋值给 Functional，因为 FunctionalAnnotation 没有明确说明实现 Functional 接口。
         * 唯一的惊喜是，Java 8 允许我们将函数赋值给接口，这样的语法更加简单漂亮。
         *
         * java.util.function 包旨在创建一组完整的目标接口，使得我们一般情况下不需再定义自己的接口。
         * 这主要是因为基本类型会产生一小部分接口。 如果你了解命名模式，顾名思义就能知道特定接口的作用。、
         *
         *
         * 以下是基本命名准则：
         *
         * 如果只处理对象而非基本类型，
         * 名称则为 Function，Consumer，Predicate 等。参数类型通过泛型添加。
         *
         * 如果接收的参数是基本类型，
         * 则由名称的第一部分表示，如 LongConsumer，DoubleFunction，IntPredicate 等，但基本 Supplier 类型例外。
         *
         * 如果返回值为基本类型，
         * 则用 To 表示，如 ToLongFunction <T> 和 IntToLongFunction。
         *
         * 如果返回值类型与参数类型一致，
         * 则是一个运算符：单个参数使用 UnaryOperator，两个参数使用 BinaryOperator。
         *
         * 如果接收两个参数且返回值为布尔值，则是一个谓词（Predicate）。
         *
         * 如果接收的两个参数类型不同，则名称中有一个 Bi。
         *
         * 下表描述了 java.util.function 中的目标类型（包括例外情况）：
         *
         */
        FunctionalAnnotation fa =
                new FunctionalAnnotation();
        Functional f = fa::goodbye;
        FunctionalNoAnn fna = fa::goodbye;
        //Functional fac = fa; // Incompatible
        Functional fl = a -> "Goodbye, " + a;
        FunctionalNoAnn fnal = a -> "Goodbye, " + a;
    }
}
